package com.superbit.web.servlet;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.servlet.FrameworkServlet;

import com.superbit.core.exception.BaseRuntimeException;
import com.superbit.core.exception.BusinessException;
import com.superbit.core.exception.NoFitRecordExcepiton;
import com.superbit.core.exception.ParamInvalidException;
import com.superbit.core.exception.ServerConfigException;
import com.superbit.core.exception.ServerErrorException;
import com.superbit.model.feature.MessageLogService;
import com.superbit.web.excep.AccessBusyException;
import com.superbit.web.excep.AccessLimitException;
import com.superbit.web.excep.ErrorCodeConstant;
import com.superbit.web.excep.NoLoginException;
import com.superbit.web.utils.JsonResponseUtil;

import net.sf.json.JSONObject;

@WebServlet("/exceptionDisposer")
public class ExceptionDisposer extends HttpServlet {
	private static final long serialVersionUID = -3501492062704899289L;
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String errcode = null;
		String errmessage = null;
		Throwable exp = null; //错误异常
		
		Integer status = (Integer)req.getAttribute("javax.servlet.error.status_code");
		if(400==status){
			//用户输入命令参数错误
			errcode =  ErrorCodeConstant.PARAMINVALID;
			errmessage = "Param Invalid";
		}else if(404==status){
			//用户输入URL地址错误
			errcode =  ErrorCodeConstant.PAGENOTFOUND;
			errmessage = "Page Not Fund";
		}else if(500==status){
			Throwable throwable = (Throwable)req.getAttribute("javax.servlet.error.exception");
			if(throwable!=null){
				exp = throwable.getCause();
				if(exp==null){
					exp = throwable;
				}
			}
		}
		
		if(exp!=null){
			if(exp instanceof BaseRuntimeException){
				Throwable cause = exp.getCause();
				while(cause!=null&&cause instanceof BaseRuntimeException){
					exp = cause;
					cause = exp.getCause();
				}
			}
			
			if(exp instanceof BusinessException){ //标准业务异常
				BusinessException  e = (BusinessException)exp;
				errcode =  e.getErrorcode();
				errmessage = e.getMessage();
				//不记录日志
			}else if(exp instanceof NoLoginException){//无对应功能权限 前端收到此信息后返回登陆页面
				errcode = ErrorCodeConstant.NOTLOGIN;
				errmessage = "User Not Login";
				//不记录日志
			}else if(exp instanceof AccessLimitException){//无对应功能权限 前端收到此信息后返回登陆页面
				errcode = ErrorCodeConstant.ACCESSLIMIT;
				errmessage = "Acess Forbiden";
				//不记录日志
			}else if(exp instanceof AccessBusyException){//访问过于频繁 
				errcode = ErrorCodeConstant.ACCESSTOOBUSY;
				errmessage = "Acess Too Busy";
				this.logAccessBusyError((AccessBusyException)exp, req); 
			}else if(exp instanceof ParamInvalidException){//提交参数格式有误
				errcode = ErrorCodeConstant.PARAMINVALID;
				errmessage = exp.getMessage();
				logUserError(errcode,exp, req);
			}else if(exp instanceof IllegalStateException){//参数不合法
				errcode = ErrorCodeConstant.PARAMINVALID;
				errmessage = "Param Invalid:"+exp.getMessage();
				logUserError(errcode,exp, req);
			}else if(exp instanceof NoFitRecordExcepiton){//找不到对应记录
				errcode = ErrorCodeConstant.NOFITRECORD;
				errmessage = exp.getMessage();
				logUserError(errcode,exp, req);
			}else if(exp instanceof ServerConfigException){//环境配置错误
				errcode = ErrorCodeConstant.CONFIGERROR;
				errmessage = exp.getMessage();
				logServerError(errcode,exp, req);
			}else if(exp instanceof ServerErrorException){//环境运行错误
				errcode = ErrorCodeConstant.SERVERERROR;
				errmessage = exp.getMessage();
				logServerError(errcode,exp, req);
			}else if(exp instanceof BaseRuntimeException){//标准运行时异常
				errcode = ErrorCodeConstant.SERVERERROR;
				errmessage = exp.getMessage();
				logUserError(errcode,exp, req);
			}else if(!(exp instanceof RuntimeException)){//编译时异常
				errcode = ErrorCodeConstant.ERRORTHROW;
				errmessage = exp.getMessage();
				logDevelopError(errcode,exp, req);
			}else{ //处理其他运行时异常
				//未正常捕获异常：
				if(exp instanceof NullPointerException){
					//空指针异常
					errcode = ErrorCodeConstant.NULLPOINTER;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}else if(exp instanceof ArrayIndexOutOfBoundsException){
					errcode = ErrorCodeConstant.ARRAYOUTINDEX;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}else if(exp instanceof NumberFormatException){
					errcode = ErrorCodeConstant.DATAFORMAT;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}else if(exp instanceof ClassCastException){
					errcode = ErrorCodeConstant.DATAFORMAT;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}else if(exp instanceof ArithmeticException){
					errcode = ErrorCodeConstant.MATHERROR;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}else{
					//剩余运行时异常
					errcode = ErrorCodeConstant.UNDEFINED;
					errmessage = "SERVER ERROR";
					logDevelopError(errcode, exp, req);
				}
			}
			
		}else if(errcode ==null){
			errcode =  ErrorCodeConstant.UNDEFINED;
			errmessage = "ErrorStatus "+status;
		}
		
		//向前端返回错误
		String value = JsonResponseUtil.buildNormalExcepResonpe(errcode,errmessage).toString();
		JSONObject jo = JSONObject.fromObject(value);
		resp.setContentType("text/html; charset=UTF-8");
		resp.setStatus(200);
		resp.getWriter().print(jo.toString());
		resp.getWriter().flush();
	}

	private void logDevelopError(String errorcode,Throwable exp, HttpServletRequest req) {
		logger.error("发生逻辑异常 "+errorcode+"-"+exp.getClass().getSimpleName());
//		通知开发管理人员
		Map<String,String> map = getRequestParamMap(req);
		map.put("errorcode", errorcode);
		
		MessageLogService messageLogService = this.getSpringBean(req, MessageLogService.class);
		messageLogService.logDevlopError(exp,map);
	}

	private void logServerError(String errorcode,Throwable exp, HttpServletRequest req) {
		logger.error("发生系统异常："+errorcode+"-"+exp.getClass().getSimpleName());
		//通知系统管理员
		Map<String,String> map = getRequestParamMap(req);
		map.put("errorcode", errorcode);
		
		MessageLogService messageLogService = this.getSpringBean(req, MessageLogService.class);
		messageLogService.logServerError(exp,map);
	}

	private void logUserError(String errorcode,Throwable exp, HttpServletRequest req) {
//		logger.error("发生用户异常  "+errorcode+"-"+exp.getClass().getSimpleName());
//		Integer userid = SessionUserUtils.getLoginUserId(req.getSession());
//		if(userid == null)userid = (Integer) req.getAttribute("userid");
//		String remoteIP = CommonUtils.getRemoteHost(req);
//		Map<String,String> map = getRequestParamMap(req);
//		map.put("errorcode", errorcode);
//		
//		MessageLogService messageLogService = this.getSpringBean(req, MessageLogService.class);
//		messageLogService.logUserError(userid,remoteIP,exp,map);
	}

	private void logAccessBusyError(AccessBusyException exp, HttpServletRequest req) {
		logUserError(ErrorCodeConstant.ACCESSTOOBUSY,exp,req);
		req.getSession().invalidate();
		int userid = exp.getLonginUserId();
		int locktime = 1000*3600;
//		UserAccountService urs = SpringCloudBeanFactory.getBean(UserAccountService.class);
//		urs.lockOrUnlockUser(userid, (byte)3, System.currentTimeMillis()+locktime);
	}

	private <T> T getSpringBean(ServletRequest request,Class<T> cls){
		ServletContext sc = request.getServletContext();
		ApplicationContext ac = (ApplicationContext)sc.getAttribute(FrameworkServlet.SERVLET_CONTEXT_PREFIX+"springMVC");
		return ac.getBean(cls);
	}
	
	/**获取参数数据
	 * @param req
	 * @return
	 */
	private Map<String,String> getRequestParamMap(HttpServletRequest req){
		Map<String,String[]> map = req.getParameterMap();
		Map<String,String> map2 = new HashMap<String,String>();
		for(String key : map.keySet()){
			String[] values = map.get(key);
			if(values.length==1){
				map2.put(key, values[0]);
			}else{
				map2.put(key, Arrays.asList(values).toString());
			}
		}
		map2.remove("newpwd");
		map2.remove("oldpwd");
		map2.remove("password");
		map2.remove("foundpwd");
		return map2;
	}
}